import {Button, DatePicker, Input, InputRef, Space, TableColumnProps, TablePaginationConfig, theme} from "antd";
import React, {Key, useRef, useState} from "react";
import {CalendarOutlined, SearchOutlined} from "@ant-design/icons";
import Highlighter from "react-highlight-words"
import {ColumnFilterItem, FilterValue, SorterResult} from "antd/es/table/interface";
import {createUseStyles} from "react-jss";
import {GlobalToken} from "antd/es/theme/interface";
import {Order, Pageable, Sort} from "../utils/Page";
import dayjs, {Dayjs} from "dayjs";
import {OffsetDateTime} from "@js-joda/core";
import {DATE_WITH_TIME_FORMATER, YEAR_MONTH_DAY_FORMATER} from "./Date";

export interface BuildTableSearchTextColumnOptions<DT> {
    placeholder?: string
    handleSearch?: (text: string, dataIndex: keyof DT) => Promise<void> | void
}

export type DateRange = [Dayjs, Dayjs]

export interface BuildTableSearchDateRangeColumnOptions<DT> {
    placeholder?: string
    handleSearch: (value: DateRange | undefined, dataIndex: keyof DT) => Promise<void> | void
}


const useStyles = createUseStyles({
    searchIconContainer: (props: GlobalToken & {
        hasValue?: boolean
    }) => ({
        borderColor: props.hasValue ? props.colorPrimaryBorder : undefined,
        borderRadius: "4px",
        borderWidth: "1px",
        borderStyle: props.hasValue ? "solid" : undefined,
        padding: "0 8px"
    })
})

export function useTableFilterDateRangeColumnProps<DT, K extends keyof DT = keyof DT>(dataIndex: K, options: BuildTableSearchDateRangeColumnOptions<DT>): TableColumnProps<DT> {
    const ref = useRef<any>(null);
    const [value, setValue] = useState<[Dayjs, Dayjs]>()
    return {
        filterDropdown: ({setSelectedKeys, selectedKeys, confirm, clearFilters, close}) => {

            async function handleSearch(value: DateRange | undefined, dataIndex: K) {
                setValue(value)
                confirm()

                if (!options.handleSearch) {
                    return Promise.resolve()
                } else {
                    let handleSearchResult = options.handleSearch(value, dataIndex);
                    if (handleSearchResult instanceof Promise) {
                        await handleSearchResult
                    } else {
                        return Promise.resolve()
                    }
                }


            }

            function selectedKeysToValue(selectedKeys: Key[]) {
                return selectedKeys.length == 2 ? [dayjs(selectedKeys[0] as string), dayjs(selectedKeys[1] as string)] as [Dayjs, Dayjs] : undefined
            }

            return (
                <div style={{padding: 8}} onKeyDown={(e) => e.stopPropagation()}>
                    <DatePicker.RangePicker
                        allowClear={false}
                        size={"small"}
                        ref={ref}
                        value={selectedKeysToValue(selectedKeys)}
                        onChange={(dates) => {
                            let mySelectedKeys = dates?.map(it => it?.format()).filter(it => !!it).map(it => it!!) ?? [];
                            setSelectedKeys(mySelectedKeys)
                        }}
                        style={{marginBottom: 8, display: 'block'}}
                    />
                    <Space>
                        <Button
                            type="primary"
                            onClick={() => {
                                // setSelectedKeys
                                let selectedKeysToValue1 = selectedKeysToValue(selectedKeys);
                                handleSearch(selectedKeysToValue1, dataIndex)
                            }}
                            icon={<SearchOutlined/>}
                            size="small"
                            style={{width: 90}}
                        >
                            查询
                        </Button>
                        <Button
                            onClick={() => clearFilters && (() => {
                                clearFilters()
                                setValue(undefined)
                            })()}
                            size="small"
                            style={{width: 90}}
                        >
                            重置
                        </Button>
                        <Button
                            type="link"
                            size="small"
                            onClick={() => {
                                close();
                            }}
                        >
                            关闭
                        </Button>
                    </Space>
                </div>
            );
        },
        filterIcon: (filtered: boolean) => (
            <CalendarOutlined style={{color: value ? '#1677ff' : undefined}}/>
        ),
        filterDropdownProps:{
            onOpenChange: (visible) => {
                if (visible) {
                    setTimeout(() => ref.current?.focus(), 100);
                }
            }
        }
    };
}

export function useTableSearchTextColumnProps<DT, K extends keyof DT = keyof DT>(dataIndex: K, options: BuildTableSearchTextColumnOptions<DT>): TableColumnProps<DT> {
    const searchInput = useRef<InputRef>(null);
    const [searchText, setSearchText] = useState("")
    const themeData = theme.useToken();
    let styles = useStyles({...themeData.token, hasValue: !!searchText});

    // @ts-ignore
    // @ts-ignore
    // @ts-ignore
    return {
        filterDropdown: ({setSelectedKeys, selectedKeys, confirm, clearFilters, close}) => {
            async function handleSearch(text: string, dataIndex: K) {
                setSearchText(text)
                confirm()
                if (!options.handleSearch) return Promise.resolve()
                let handleSearchResult = options.handleSearch(text, dataIndex);
                if (handleSearchResult instanceof Promise) {
                    await handleSearchResult
                } else {
                    return Promise.resolve()
                }
            }

            return (
                <div style={{padding: 8}} onKeyDown={(e) => e.stopPropagation()}>
                    <Input
                        ref={searchInput}
                        placeholder={options.placeholder}
                        value={selectedKeys[0]}
                        onChange={(e) => setSelectedKeys(e.target.value ? [e.target.value] : [])}
                        onPressEnter={() => handleSearch((selectedKeys as string[])[0], dataIndex)}
                        style={{marginBottom: 8, display: 'block'}}
                    />
                    <Space>
                        <Button
                            type="primary"
                            onClick={() => {
                                return handleSearch((selectedKeys as string[])[0], dataIndex);
                            }}
                            icon={<SearchOutlined/>}
                            size="small"
                            style={{width: 90}}
                        >
                            查询
                        </Button>
                        <Button
                            onClick={() => clearFilters && (() => {
                                clearFilters()
                            })()}
                            size="small"
                            style={{width: 90}}
                        >
                            重置
                        </Button>
                        <Button
                            type="link"
                            size="small"
                            onClick={() => {
                                close();
                            }}
                        >
                            关闭
                        </Button>
                    </Space>
                </div>
            );
        },
        filterIcon: (filtered: boolean) => (
            <Space className={styles.searchIconContainer}>
                <SearchOutlined style={{color: filtered ? '#1677ff' : undefined}}/>
                {searchText ? <span>{searchText}</span> : undefined}
            </Space>
        ),
        filterDropdownProps:{
          onOpenChange(visible){
              if (visible) {
                  setTimeout(() => searchInput.current?.focus(), 100);
              }
          }
        },
        render: (text) =>
            searchText ? (
                // @ts-ignore
                <Highlighter
                    highlightStyle={{backgroundColor: '#ffc069', padding: 0}}
                    searchWords={[searchText]}
                    autoEscape
                    textToHighlight={text ? text.toString() : ''}
                />
            ) : (
                text
            ),
    };
}

export function castFilterValue(value: FilterValue | null): string | undefined {
    return value ? (value as string[])[0] || undefined : undefined
}

export function sorterToSort(sorter: SorterResult<any> | SorterResult<any>[] | undefined) {
    if (!sorter) {
        return Sort.empty
    } else {
        let orders;
        if (sorter instanceof Array) {
            orders = sorter.map(sortResultToOrder)
        } else {
            orders = [sortResultToOrder(sorter)]
        }
        return new Sort(orders.filter(it => !!it).map(it => it!!))
    }
}

function sortResultToOrder(sorterResult: SorterResult<any>) {
    if (sorterResult.field) {
        return new Order(sorterResult.field as string, sorterResult.order ? (sorterResult.order === "ascend") : undefined)
    } else {
        return null
    }
}

export function mergePaginationAndPageable(tablePagination: TablePaginationConfig, pageable: Pageable, sorter?: SorterResult<any> | SorterResult<any>[]) {
    return Pageable.from(
        pageable,
        {
            page: tablePagination.current,
            size: tablePagination.pageSize,
            sort: sorterToSort(sorter)
        }
    )
}







export const AntdTableColumnFilterSearches = {
    columnFilterByOptionText: (input: string, record: ColumnFilterItem) => {
        return (record.text as string).includes(input)
    },
}

export const AntdTableColumnRenders = {
    dateTimeStringColumnRender: (value?: string) => {
        if (value) {
            return OffsetDateTime.parse(value).format(DATE_WITH_TIME_FORMATER);
        } else {
            return null
        }
    },
    dateTimeColumnRender(value?:OffsetDateTime){
        return value?value.format(DATE_WITH_TIME_FORMATER):null
    },
    dateColumnRender: (value?: string) => {
        if (value) {
            return OffsetDateTime.parse(value).format(YEAR_MONTH_DAY_FORMATER);
        } else {
            return null
        }
    },
}

export function buildSortCompareFunction<T>(fieldName:keyof T){
    return (a: T, b: T,) => {
        let valueA = a[fieldName];
        let valueB = b[fieldName];
        if (typeof valueA === "string" && typeof valueB === "string") {
            return valueA.localeCompare(valueB);
        } else if (typeof valueA === "number" && typeof valueB === "number") {
            return valueA - valueB
        } else {
            return JSON.stringify(valueA).localeCompare(JSON.stringify(valueB))
        }
    }
}
